package com.hjw.httpclient.retry;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.junit.Before;
import org.junit.Test;

import java.net.URISyntaxException;

/**
 * 重试类：主要针对异常进行重试 （请求不可达）
 * 连接超时/读取响应超时
 * <p>
 * 模拟方式：服务端打个断点，让客户端长时间得不到响应自动抛出read time out 异常，进行重试
 *
 * @author hjwStrart
 * @time 2022-11-23 20:06
 * @version: 1.0
 */
public class MyRetryException {

    private RequestConfig requestConfig = null;
    private PoolingHttpClientConnectionManager cm = null;
    private static final int MAX_RETRY_COUNT = 3;


    @Before
    public void init() {
        requestConfig = RequestConfig.custom()
                .setConnectTimeout(5000)
                .setSocketTimeout(3000)
                .setConnectionRequestTimeout(5000)
                .build();
        cm = new PoolingHttpClientConnectionManager();
        cm.setMaxTotal(20);
        cm.setDefaultMaxPerRoute(2);
    }

    @Test
    public void method() throws Exception {
        /*
        org.apache.http.client.HttpRequestRetryHandler#retryRequest(IOException exception, int executionCount, HttpContext context)
        参数解读：
            exception：失败异常类型
            executionCount：重试次数
            context：当前请求的上下文内容  (测试打印的null，具体不太清除，等以后用到了再说)
            补充：httpcontent可以用来判断此请求是否是幂等接口，是幂等接口可以重试，否则不能重试
         */
        CloseableHttpClient closeableHttpClient = HttpClientBuilder.create()
                .setRetryHandler((exception, executionCount, context) -> {
                    if (executionCount >= MAX_RETRY_COUNT) {
                        // Do not retry if over max retry count
                        return false;
                    }
                    HttpClientContext clientContext = HttpClientContext.adapt(context);
                    HttpRequest request = clientContext.getRequest();
                    boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
                    if (idempotent) {
                        // Retry if the request is considered idempotent 是否是幂等请求
                        System.out.println("异常原因：" + exception.getMessage());
                        System.out.println("异常栈信息：");
                        exception.printStackTrace();
                        System.out.println("当前重试次数：" + executionCount);
                        ObjectMapper mapper = new ObjectMapper();
                        String contextStr = null;

                        try {
                            contextStr = mapper.writeValueAsString(context);
                        } catch (JsonProcessingException e) {
                            e.printStackTrace();
                        }
                        System.out.println("当前请求的上下文内容：" + contextStr);
                        return true;
                    }
                    return false;
                }).setConnectionManager(cm)
                .setDefaultRequestConfig(requestConfig)
                .build();
        String urlStr = "http://localhost:8080/form/get";
        URIBuilder uriBuilder = new URIBuilder(urlStr);
        uriBuilder.addParameter("userName", "黄嘉威");
        uriBuilder.addParameter("userPwd", "admin");
        HttpGet httpGet = new HttpGet(uriBuilder.build());
        CloseableHttpResponse execute = closeableHttpClient.execute(httpGet);
        if (execute.getStatusLine().getStatusCode() == 200) {
            System.out.println("请求成功！！！");
        }
    }
}
